<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2023/12/13
 * Time: 11:46
 */
namespace app\api\controller\v3;

use Exception;
use app\api\controller\v3\ProfitSharingCurlController;
class ProfiTharingController
{

    // 商户mchid
    private $mch_id = '1652272678';//服务商户号
    private $sp_appid = "wxd40250e8dfabab46";//服务商appid
    private $serial_no = '133ACD41C8CEB29C0B7407317E998358FB96FE48';//证书序列号 合作伙伴的
    private $mch_private_key = "D:/zjwwww/klch/public/uploads/wx/apiclient_key.pem";//私钥 合作伙伴的
    private $public_key_path = "D:/zjwwww/klch/public/uploads/wx/apiclient_cert.pem";//支付平台公钥 合作伙伴的
    private $sub_appid = "";//商户appid
    private $notify_url = '';
    private $sp_mchid = "1653284709";//湖南全软软件科技股份有限公司 这个服务商户号到时候要做张表存着，根据用户选的车去变量
    private $apiKey = "GAwi38h0YB2OH9a4ude18zM59DUsTcQb";//V2秘钥

    private $wxConfig = null;
    private $sign = null;
    private $curl = null;


    public function __construct()
    {
//        $this->wxConfig = $this->wxConfig();
//        $this->sign = new ProfitSharingSign();
        $this->curl = new ProfitSharingCurlController();
    }


    /**
     * 请求单次分账接口
     * 单词分账分给单个商户
     * @return array
     * @throws Exception
     * @throws \Exception
     */
    public function profitSharing($profitSharingOrder = [])
    {
        //分账接收方数组
         $receivers = [
              'type' => 'MERCHANT_ID',
              'account' => $this->mch_id,
              'amount' => 10*0.1*100,  //这里注意不能大过（支付金额*分账比例）之后的金额
              'description' => '测试分账',  //备注 不可以少
          ];
        //profitSharingOrder传递的参数
         $profitSharingOrder = [
             'sub_mchid' => $this->sp_mchid,
             'transaction_id' => "4200002089202312145397438145",
             'order_no' => 'wx1702525009944293751',//“自己生成的订单号”,
             'receivers' => json_encode($receivers,256|64),  //接收方数组  json格式
         ];
        $postArr = array(
            'appid'=>$this->sp_appid,
            'mch_id'=>$this->mch_id,
            'sub_mch_id'=>$this->sp_mchid,
            'nonce_str'=>md5(time() . rand(1000, 9999)),
            'out_order_no'=>$profitSharingOrder['order_no'].'11',  //自己生成的订单号
            'transaction_id'=>$profitSharingOrder['transaction_id'],  //微信支付订单号
            'receivers'=>$profitSharingOrder['receivers'],  //接收方  json格式
        );
        if( isset($profitSharingOrder['sub_appid']) ) $postArr['sub_appid'] = $profitSharingOrder['sub_appid'];

        // 2.生成签名
        $sign = $this->getSign($postArr, 'HMAC-SHA256', $this->apiKey);

        $postArr['sign'] = $sign;
        // 3.发送请求
        $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing';
        $postXML = $this->arrayToXml($postArr);
        $opts = array(
            CURLOPT_HEADER    => 0,
            CURLOPT_SSL_VERIFYHOST    => false,
            CURLOPT_SSLCERTTYPE   => 'PEM', //默认支持的证书的类型，可以注释
            CURLOPT_SSLCERT   => $this->public_key_path,
            CURLOPT_SSLKEY    => $this->mch_private_key,
        );
        $curl_res = $this->curl->setOption($opts)->post($url,$postXML);

        $ret = $this->toArray($curl_res);
        if($ret['return_code']=='SUCCESS' and $ret['result_code']=='SUCCESS'){
            //保存分账订单状态或者别的操作
            return $ret;
        }
        return $ret;
    }


    /**
     * @function 请求单次分账接口
     * @param $profitSharingOrders array 待分账订单
     * @param $profitSharingAccounts array 分账接收方
     * @return array
     * 这个方法可同时分给多个商户号
     * @throws Exception
     */
    public function profitSharing2($profitSharingOrders,$profitSharingAccounts)
    {
        if(empty($profitSharingOrders)){
            throw new Exception('没有待分帐订单');
        }
        if(empty($profitSharingAccounts)){
            throw new Exception('接收分账账户为空');
        }

        //1.设置分账账号
        $receivers = array();
        foreach ($profitSharingAccounts as $profitSharingAccount)
        {
            $tmp = array(
                'type'=>$profitSharingAccount['type'],
                'account'=>$profitSharingAccount['account'],
                'amount'=>intval($profitSharingAccount['amount']),
                'description'=>$profitSharingAccount['desc'],
            );
            $receivers[] = $tmp;
        }
        $receivers = json_encode($receivers,JSON_UNESCAPED_UNICODE);

        $totalCount = count($profitSharingOrders);
        $successCount = 0;
        $failCount = 0;
        $now = time();

        foreach ($profitSharingOrders as $profitSharingOrder)
        {
            //2.生成签名
            $postArr = array(
                'appid'=>$this->sp_appid,
                'mch_id'=>$this->mch_id,
                'sub_mch_id'=>$this->sp_mchid,
//                'sub_appid'=>$this->wxConfig['sub_app_id'],
                'nonce_str'=>md5(time() . rand(1000, 9999)),
                'transaction_id'=>$profitSharingOrder['trans_id'],
                'out_order_no'=>$profitSharingOrder['order_no'].$profitSharingOrder['ticket_no'],
                'receivers'=>$receivers,
            );

            $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->apiKey);
            $postArr['sign'] = $sign;

            //3.发送请求
            $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing';
            $postXML = $this->toXml($postArr);
//            Ilog::DEBUG("profitSharing.postXML: " . $postXML);

            $opts = array(
                CURLOPT_HEADER    => 0,
                CURLOPT_SSL_VERIFYHOST    => false,
                CURLOPT_SSLCERTTYPE   => 'PEM', //默认支持的证书的类型，可以注释
                CURLOPT_SSLCERT   => $this->public_key_path,
                CURLOPT_SSLKEY    => $this->mch_private_key,
            );
//            Ilog::DEBUG("profitSharing.opts: " . json_encode($opts));

            $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
//            Ilog::DEBUG("profitSharing.curl_res: " . $curl_res);

            $ret = $this->toArray($curl_res);
            if($ret['return_code']=='SUCCESS' and $ret['result_code']=='SUCCESS')
            {
                //更新分账订单状态
                $params = array();
                $params['order_no'] =  $profitSharingOrder['order_no'];
                $params['trans_id'] =  $profitSharingOrder['trans_id'];
                $params['ticket_no'] =  $profitSharingOrder['ticket_no'];

                $data = array();
                $data['profitsharing'] = $receivers;
                $data['state'] = 2;
//                pdo_update('ticket_orders_profitsharing',$data,$params);
                $successCount++;

            }else{
                $failCount++;
            }

        }

        return array('processTime'=>date('Y-m-d H:i:s',$now),'totalCount'=>$totalCount,'successCount'=>$successCount,'failCount'=>$failCount);

    }


    /**
     * @function 查询分账结果
     * @param $trans_id string 微信支付单号
     * @param $out_order_no string 分账单号
     * @return array|false
     * @throws Exception
     */
    public function query($trans_id,$out_order_no)
    {
        //1.生成签名
        $postArr = array(
            'mch_id'=>$this->mch_id,
            'sub_mch_id'=>$this->sp_mchid,
            'transaction_id'=>$trans_id,
            'out_order_no'=>$out_order_no,
            'nonce_str'=>md5(time() . rand(1000, 9999)),
        );

        $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->apiKey);
        $postArr['sign'] = $sign;


        //2.发送请求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingquery';
        $postXML = $this->toXml($postArr);
//        Ilog::DEBUG("query.postXML: " . $postXML);

        $curl_res = $this->curl->post($url,$postXML);
//        Ilog::DEBUG("query.curl_res: " . $curl_res);

        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 添加分账接收方
     * @param $profitSharingAccount array 分账接收方
     * @return array|false
     * @throws Exception
     */
    public function addReceiver($profitSharingAccount = [])
    {
        //1.接收分账账户
        $receiver = array(
            'type'=>'MERCHANT_ID',
            'account'=>"1463846202",//1652272678
            'name'=>"快乐车行（北京）科技有限公司",
            'relation_type'=>"SERVICE_PROVIDER",
        );
//        $receiver = array(
//            'type' => 'PERSONAL_OPENID',
//            'account' => "o_7H-5e8kqv1HY9Pgx2mu3KKiuAI",
//            'name' => '喻飒婵',
//            'relation_type' => 'USER',
//        );
        $receiver = json_encode($receiver,JSON_UNESCAPED_UNICODE);

        //2.生成签名
        $postArr = array(
            'mch_id'=>$this->mch_id,//1652272678
            'sub_mch_id'=>$this->sp_mchid,//1653284709  特约商户的商户号
            'appid'=>$this->sp_appid,
            'nonce_str'=>md5(time() . rand(1000, 9999)),
            'receiver'=>$receiver
        );

        $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->apiKey);

        $postArr['sign'] = $sign;
        //3.发送请求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver';
        $postXML = $this->arrayToXml($postArr);

//        Ilog::DEBUG("addReceiver.postXML: " . $postXML);
        $curl_res = $this->curl->post($url,$postXML);

//        Ilog::DEBUG("addReceiver.curl_res: " . $curl_res);
        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 删除分账接收方
     * @param $profitSharingAccount array 分账接收方
     * @return array|false
     * @throws Exception
     */
    public function removeReceiver($profitSharingAccount)
    {
        //1.接收分账账户
        $receiver = array(
            'type'=>$profitSharingAccount['type'],
            'account'=>$profitSharingAccount['account'],
            'name'=>$profitSharingAccount['name'],
        );
        $receiver = json_encode($receiver,JSON_UNESCAPED_UNICODE);

        //2.生成签名
        $postArr = array(
            'appid'=>$this->sp_appid,
            'mch_id'=>$this->mch_id,
            'sub_mch_id'=>$this->sp_mchid,
//            'sub_appid'=>$this->wxConfig['sub_app_id'],
            'nonce_str'=>md5(time() . rand(1000, 9999)),
            'receiver'=>$receiver
        );

        $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->apiKey);
        $postArr['sign'] = $sign;

        //3.发送请求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver';
        $postXML = $this->toXml($postArr);
//        Ilog::DEBUG("removeReceiver.postXML: " . $postXML);

        $curl_res = $this->curl->post($url,$postXML);
//        Ilog::DEBUG("removeReceiver.curl_res: " . $curl_res);

        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 完结分账
     * @param $profitOrder array 分账订单
     * @param $description string 完结分账描述
     * @return array|false
     * @throws Exception
     */
    public function finish($profitOrder,$description='分账完结')
    {
        $ret = array();
        if(!empty($profitOrder))
        {
            //1.签名
            $postArr = array(
                'mch_id'=>$this->mch_id,
                'sub_mch_id'=>$this->sp_mchid,
                'appid'=>$this->sp_appid,
                'nonce_str'=>md5(time() . rand(1000, 9999)),
                'transaction_id'=>$profitOrder['trans_id'],
                'out_order_no'=>'finish'.'_'.$profitOrder['order_no'],
                'description'=>$description,
            );

            $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
            $postArr['sign'] = $sign;


            //2.请求
            $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish';
            $postXML = $this->toXml($postArr);
//            Ilog::DEBUG("finish.postXML: " . $postXML);

            $opts = array(
                CURLOPT_HEADER    => 0,
                CURLOPT_SSL_VERIFYHOST    => false,
                CURLOPT_SSLCERTTYPE   => 'PEM', //默认支持的证书的类型，可以注释
                CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
            );
//            Ilog::DEBUG("finish.opts: " . json_encode($opts));

            $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
//            Ilog::DEBUG("finish.curl_res: " . $curl_res);

            $ret = $this->toArray($curl_res);
        }

        return $ret;
    }


    /**
     * @function 分账回退
     * @param $profitOrder array 分账订单
     * @return array
     * @throws Exception
     */
    public function profitSharingReturn($profitOrder)
    {
        $ret = array();
        if(!empty($profitOrder) and $profitOrder['channel']==1)
        {
            $accounts = json_decode($profitOrder['profitsharing'],true);
            foreach ($accounts as $account)
            {
                //1.签名
                $postArr = array(
                    'appid'=>$this->sp_appid,
                    'mch_id'=>$this->mch_id,
                    'sub_mch_id'=>$this->sp_mchid,
//                    'sub_appid'=>$this->wxConfig['sub_app_id'],
                    'nonce_str'=>md5(time() . rand(1000, 9999)),
                    'out_order_no'=>$profitOrder['order_no'].$profitOrder['ticket_no'],
                    'out_return_no'=>'return_'.$profitOrder['order_no'].$profitOrder['ticket_no'].'_'.$account['account'],
                    'return_account_type'=>'MERCHANT_ID',
                    'return_account'=>$account['account'],
                    'return_amount'=>$account['amount'],
                    'description'=>'用户退款',
                    'sign_type'=>'HMAC-SHA256',
                );

                $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->apiKey);
                $postArr['sign'] = $sign;


                //2.请求
                $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn';
                $postXML = $this->toXml($postArr);
//                Ilog::DEBUG("profitSharingReturn.postXML: " . $postXML);

                $opts = array(
                    CURLOPT_HEADER    => 0,
                    CURLOPT_SSL_VERIFYHOST    => false,
                    CURLOPT_SSLCERTTYPE   => 'PEM', //默认支持的证书的类型，可以注释
                    CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                    CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
                );
//                Ilog::DEBUG("profitSharingReturn.opts: " . json_encode($opts));

                $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
//                Ilog::DEBUG("profitSharingReturn.curl_res: " . $curl_res);

                $ret[] = $this->toArray($curl_res);
            }

        }
        return $ret;
    }


    /**
     * @function 回退结果查询
     * @param $order_no string 本地订单号
     * @param $ticket_no string 本地票号
     * @return array|false
     * @throws \Exception
     */
    public function returnQuery($order_no,$ticket_no)
    {
        $ret = array();
        $profitOrder = pdo_fetch("SELECT * FROM zc_ticket_orders_profitsharing WHERE order_no='{$order_no}' AND ticket_no='{$ticket_no}'");
        if($profitOrder['channel']==1 and $profitOrder['state']==2)
        {
            $accounts = json_decode($profitOrder['profitsharing'],true);
            foreach ($accounts as $account)
            {
                //1.签名
                $postArr = array(
                    'appid'=>$this->sp_appid,
                    'mch_id'=>$this->mch_id,
                    'sub_mch_id'=>$this->sp_mchid,
                    'nonce_str'=>md5(time() . rand(1000, 9999)),
                    'out_order_no'=>$profitOrder['order_no'].$profitOrder['ticket_no'],
                    'out_return_no'=>'return_'.$profitOrder['order_no'].$profitOrder['ticket_no'].'_'.$account['account'],
                    'sign_type'=>'HMAC-SHA256',
                );

                $sign = $this->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
                $postArr['sign'] = $sign;

                //2.请求
                $url = 'https://api.mch.weixin.qq.com/pay/profitsharingreturnquery';
                $postXML = $this->toXml($postArr);
//                Ilog::DEBUG("returnQuery.postXML: " . $postXML);

                $curl_res = $this->curl->post($url,$postXML);
//                Ilog::DEBUG("returnQuery.curl_res: " . $curl_res);

                $ret[] = $this->toArray($curl_res);
            }

        }
        return $ret;
    }


    /**
     * @function 将array转为xml
     * @param array $values
     * @return string|bool
     * @author xiewg
     **/
    public function toXml($values)
    {
        if (!is_array($values) || count($values) <= 0) {
            return false;
        }

        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml.="<".$key.">".$val."</".$key.">";
            } else {
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    //数组转换成xml
    public function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . $this->arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }


    /**
     * @function 将xml转为array
     * @param string $xml
     * @return array|false
     * @author xiewg
     */
    public function toArray($xml)
    {
        if (!$xml) {
            return false;
        }

        // 检查xml是否合法
        $xml_parser = xml_parser_create();
        if (!xml_parse($xml_parser, $xml, true)) {
            xml_parser_free($xml_parser);
            return false;
        }

        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);

        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        return $data;
    }



    /**
     * 根据Url传递的参数，生成签名字符串
     * @param array $param
     * @param string $signType
     * @param $md5Key
     * @return string
     * @throws \Exception
     */
    public function getSign(array $param, $signType = 'MD5', $md5Key)
    {
        $values = $this->paraFilter($param);
        $values = $this->arraySort($values);
        $signStr = $this->createLinkstring($values);
        $signStr .= '&key=' . $md5Key;
        switch ($signType)
        {
            case 'MD5':
                $sign = md5($signStr);
                break;
            case 'HMAC-SHA256':
                $sign = hash_hmac('sha256', $signStr, $md5Key);
                break;
            default:
                $sign = '';
        }

        return strtoupper($sign);
    }


    /**
     * 移除空值的key
     * @param $para
     * @return array
     */
    public function paraFilter($para)
    {
        $paraFilter = array();
        foreach ($para as $key => $val) {
                if ($val == "") {
                    continue;

                } else {
                    if (!is_array($para[$key])) {
                        $para[$key] = is_bool($para[$key]) ? $para[$key] : trim($para[$key]);
                    }

                    $paraFilter[$key] = $para[$key];
                }
            }
            return $paraFilter;
        }


    /**
     * @function 对输入的数组进行字典排序
     * @param array $param 需要排序的数组
     * @return array
     * @author helei
     */
    public function arraySort(array $param)
    {
        ksort($param);
        reset($param);
        return $param;
    }


    /**
     * @function 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param array $para 需要拼接的数组
     * @return string
     * @throws \Exception
     */
    public function createLinkString($para)
    {
        if (! is_array($para)) {
            throw new \Exception('必须传入数组参数');
        }

        reset($para);
        $arg  = "";
        foreach ($para as $key => $val){
            if (is_array($val)) {
                continue;
            }

            $arg.=$key."=".urldecode($val)."&";
        }
        //去掉最后一个&字符
//        $arg = substr($arg, 0, count($arg) - 2);
        $arg = substr($arg, 0, -1);
        //如果存在转义字符，那么去掉转义
//        if (get_magic_quotes_gpc()) {
//            $arg = stripslashes($arg);
//        }
        $arg = stripslashes($arg);


        return $arg;
    }

}